﻿using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;

namespace Fluffy.Archive.DragDropEngine
{
	public class ZipStream : IStream
	{
		private readonly SyncQueue<byte[]> _data = new SyncQueue<byte[]>();

		private bool _isStarted;
		private byte[] _lastReadPart;

		public event Action OnFirstRead;
		public event Action<long> ProgressChanged;

		public void Add(byte[] part, bool isFinished)
		{
			_data.Enqueue(part, isFinished);
		}

		void IStream.Read(byte[] pv, int cb, IntPtr pcbRead)
		{
			if (!_isStarted)
			{
				if (OnFirstRead != null)
					OnFirstRead();

				_isStarted = true;
			}

			byte[] part = _lastReadPart ?? _data.Dequeue();

			if (part == null)
			{
				Marshal.WriteInt32(pcbRead, 0);
				return;
			}

			long readBytesCount;

			if (part.Length > cb)
			{
				part.Take(cb).ToArray().CopyTo(pv, 0);
				Marshal.WriteInt32(pcbRead, cb);
				readBytesCount = cb;

				_lastReadPart = part.Skip(cb).ToArray();
			}
			else
			{
				part.CopyTo(pv, 0);
				Marshal.WriteInt32(pcbRead, part.Length);
				readBytesCount = part.Length;

				_lastReadPart = null;
			}

			if (ProgressChanged != null)
				ProgressChanged(readBytesCount);
		}

		void IStream.Write(byte[] pv, int cb, IntPtr pcbWritten)
		{
			throw new NotImplementedException();
		}

		void IStream.Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
		{
			throw new NotImplementedException();
		}

		void IStream.SetSize(long libNewSize)
		{
			throw new NotImplementedException();
		}

		void IStream.CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
		{
			throw new NotImplementedException();
		}

		void IStream.Commit(int grfCommitFlags)
		{
			throw new NotImplementedException();
		}

		void IStream.Revert()
		{
			throw new NotImplementedException();
		}

		void IStream.LockRegion(long libOffset, long cb, int dwLockType)
		{
			throw new NotImplementedException();
		}

		void IStream.UnlockRegion(long libOffset, long cb, int dwLockType)
		{
			throw new NotImplementedException();
		}

		void IStream.Stat(out STATSTG pstatstg, int grfStatFlag)
		{
			throw new NotImplementedException();
		}

		void IStream.Clone(out IStream ppstm)
		{
			throw new NotImplementedException();
		}
	}
}
